# 6. docker之容器网络

# 网络模式

docker有五种网络模式

  1. bridge --net=bridge,默认网络模式
  2. host --net=host,共享宿主机网卡模式
  3. none --net=none,手动配置网卡模式
  4. container --net=container:Name/ID,共享容器网卡模式
  5. 自定义网络模式

# bridge默认网络模式

bridge --net=bridge

  1. 默认网络,Docker启动后创建一个docker0网桥,默认创建的容器也是添加到这个网桥中,这个网桥也充当容器的网关这样才能让容器跟宿主机相通,默认容器可以访问宿主机能访问的网段
  2. docker为容器创建独立的网络栈,保证容器内的进程使用独立的网络环境,实现容器之间、容器与宿主机之间的网络栈隔离。同时,通过宿主机上的docker0网桥,容器可以与宿主机乃至外界进行网络通信
  3. 容器从原理上是可以与宿主机乃至外界的其他机器通信的。同一宿主机上,容器之间都是连接到docker0这个网桥上的,它可以作为虚拟交换机使容器可以相互通信。然而,由于宿主机的IP地址与容器veth pair的 IP地址均不在同一个网段,故仅仅依靠veth pair和namespace的技术,还不足以使宿主机以外的网络主动发现容器的存在。为了使外界可以方位容器中的进程,docker采用了端口绑定的方式,也就是通过iptables的NAT,将宿主机上的端口端口流量转发到容器内的端口上

# host共享宿主机网卡模式

host --net=host

  1. 容器不会获得一个独立的network namespace,而是与宿主机共用一个。这就意味着容器不会有自己的网卡信息,而是使用宿主机的。容器除了网络,其他都是隔离的。
  2. 采用host模式的容器,可以直接使用宿主机的IP地址与外界进行通信,若宿主机具有公有IP,那么容器也拥有这个公有IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行NAT转换,而且由于容器通信时,不再需要通过linuxbridge等方式转发或者数据包的拆封,性能上有很大优势。当然,这种模式有优势,也就有劣势,主要包括以下几个方面:
    1. 最明显的就是容器不再拥有隔离、独立的网络栈。容器会与宿主机竞争网络栈的使用,并且容器的崩溃就可能导致宿主机崩溃,在生产环境中,这种问题可能是不被允许的
    2. 容器内部将不再拥有所有的端口资源,因为一些端口已经被宿主机服务、bridge模式的容器端口绑定等其他服务占用掉了
  3. 如果想让容器里面的应用使用宿主机的命名空间,就可以使用这个host模式,就不需要容器的端口映射到宿主机上,因为容器的端口会直接出现在宿主机上

创建容器,设定网络模式为host模式,并测试

docker container run -it --net=host busybox

/ # ifconfig 
docker0   Link encap:Ethernet  HWaddr 02:42:1D:0D:8F:7B  
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          inet6 addr: fe80::42:1dff:fe0d:8f7b/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:123 errors:0 dropped:0 overruns:0 frame:0
          TX packets:150 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:11013 (10.7 KiB)  TX bytes:12832 (12.5 KiB)


## 创建容器时,不设定后台启动,直接进入容器
## docker0的网卡信息跟宿主机的docker0网卡信息一模一样的

# none手动配置网卡模式

none --net=none

  1. 获取独立的network namespace,但不为容器进行任何网络配置,需要我们手动配置。
  2. 容器有独立的网络栈,但不包含任何网络配置,只具有lo这个loopback网卡用于进程通信。也就是说,none模式为容器做了最少的网络设置,但是俗话说得好“少即是多”,在没有网络配置的情况下,通过第三方工具或者手工的方式,开发这任意定制容器的网络,提供了最高的灵活性
  3. 一般用于,桥接到宿主机的网段上

创建容器,设定网络模式为host模式,并测试

docker container run -it --net=none busybox

/ # ifconfig 
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

## 创建容器时,不设定后台启动,直接进入容器
## 在这个none网络模式中,查看网卡信息,就只有lo的信息,这样就说明了需要我们手动去配置网卡,这网卡才会生效

# container共享容器网卡模式

container --net=container:Name/ID

  1. 与指定的容器使用同一个network namespace,具有同样的网络配置信息,能让两个容器同一个网卡,使用两个容器除了网络,其他都还是隔离的。
  2. 在这个网络模式下的容器,会使用其他容器的网络命名空间,其网络隔离性会处于bridge桥接模式与host模式之间。当容器共享其他容器的网络命名空间,则在这两个容器之间不存在网络隔离,而她们又与宿主机以及除此之外其他的容器存在网络隔离
  3. 这种模式下的容器可以通过localhost来同一网络命名空间下的其他容器,传输效率较高。而且这种模式还节约了一定数量的网络资源,但它并没有改变容器与外界通信的方式。在一些特殊的场景中非常有用,例如,kubernetes的pod,kubernetes为pod创建一个基础设施容器,同一pod下的其他容器都以其他容器模式共享这个基础设施容器的网络命名空间,相互之间以localhost访问,构成一个统一的整体。
  4. 一般用于需要关联的容器,比如LAMP或LNMP等

创建容器,设定网络模式为container模式,并测试

[root@localhost _data]# docker container run -it --net=container:fb8e1a0faaa2 busybox

/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:656 (656.0 B)  TX bytes:0 (0.0 B)

## 创建容器时,不设定后台启动,直接进入容器
## 结果就是,这个容器的ech0网卡的是跟fb8e1a0faaa2容器ID的容器的echo0网卡是一样的,共用的

# 自定义网络

  1. 与默认的bridge原理一样,但自定义网络具备内部DNS发现,可以通过容器名或者容器之间网络通信

实例:

docker network create so
##创建网络

docker container run -itd --net=so --name so1 busybox
##创建容器并加入so网络

docker container run -itd --net=so --name so2 busybox
##创建容器并加入so网络

docker container exec -it so2 sh
##进入我们创建好的二个容器的其中一台

/ # ping so2
PING so2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.058 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.069 ms

##确定二台容器网络相通

# 自定义网络管理命令

# 列出当前所有网络 - ls

docker network ls
选项:
	docker network ls -q
	## 列出当前所有网络的ID

# 删除网络 - rm

docker network rm 网络名或ID

# 创建网络 - create

docker network create 网络名

选项
    -d, –driver:可以指定bridge或内置网络驱动overlay,默认bridge
    –gateway:主子网的IPv4或IPv6网关
    –internal:限制外网网络连接到这个网络
    –ip-range:从一个ip范围内分配IP,使用CIDR的方式
    –subnet:使用CIDR的方式创建子网

例如:
    docker network create -d bridge frontend

    docker network create –subnet=192.168.50.0/24 br0 
    #创建192.168.50.0/24的子网

    docker network create –subnet=192.168.50.0/24 –ip-range=192.168.50.0/24 br0

    docker network create –subnet=192.168.10.0/24 –internal br1

# 清除未使用的网络 - prune

docker network prune
选项:
	docker network prune -f
	##强制

# 将容器添加进一个网络中 - connect

docker network connect 网络名 容器ID

例如:
    docker network connect br0 d7debaa899a1

    docker network connect –ip 192.168.50.101 br0 d7debaa899a1 
    ##指定容器的IP

##可以使用 docker inspect d7debaa899a1 查看 Network

# 将容器从一个网络中移除 - disconnect

docker network disconnect 网络名 容器ID

例如:
    docker network disconnect br0 d7debaa899a1

## 可以使用 docker inspect d7debaa899a1 查看 Networks

# 查看一个网络的详细信息 - inspect

docker network inspect 网络ID

# 容器网络访问原理

不多说上图

J9T4Q1.png

简单说一下,容器是怎么出来的,容器发出数据包到ech0网卡,网卡在进行转换到docker0网卡,docker0网卡在进行转行到宿主机的ech0网卡,ech0网卡在转发出去

容器数据流出流程跟流入流程

J9TvQI.png (opens new window)